﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MvcEngine.Blog.Repositories;
using MvcEngine.Blog.Models.Entities;
using MvcEngine.LinqToSqlProvider;
using MvcEngine.Core;
using System.Linq.Expressions;
using MvcEngine.Core.Helpers;
using System.Data.Linq;
using MvcEngine.Core.Pagination;
using MvcEngine.Core.Extensions;

namespace MvcEngine.Blog.LinqToSqlProvider
{
    public class BlogPostRepository : Repository, IBlogPostRepository
    {
        public BlogPost Get(Guid id)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().SingleOrDefault(p => p.Id == id);
            }
        }

        public IPagination<BlogPost> GetPosts(Guid blogId, int pageNumber, int pageSize, bool isPublished)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().Where(p => p.BlogId == blogId && p.PublishedDate.HasValue == isPublished).OrderByDescending(p => p.PublishedDate).GetPage(pageNumber, pageSize);
            }
        }

        public IPagination<BlogPost> GetPosts(Guid blogId, int pageNumber, int pageSize)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().Where(p => p.BlogId == blogId).OrderByDescending(p => p.PublishedDate).GetPage(pageNumber, pageSize);
            }
        }

        public IPagination<BlogPost> GetPostsByTag(Guid tagId, int pageNumber, int pageSize)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return (from p in contextManager.Context.Posts()
                        join pt in contextManager.Context.PostTags() on p.Id equals pt.PostId
                        join t in contextManager.Context.Tags() on pt.TagId equals t.Id
                        where t.Id == tagId && p.PublishedDate.HasValue == true
                        select p).OrderByDescending(p => p.PublishedDate).GetPage(pageNumber, pageSize);
            }
        }

        public IList<BlogPost> GetPosts(Guid blogId, int count)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().Where(p => p.BlogId == blogId && p.PublishedDate.HasValue == true).OrderByDescending(p => p.PublishedDate).Take(count).ToList();
            }
        }

        public IPagination<BlogPost> GetPostsByCategory(Guid categoryId, int pageNumber, int pageSize)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return (from p in contextManager.Context.Posts()
                        join pc in contextManager.Context.PostCategories() on p.Id equals pc.PostId
                        join c in contextManager.Context.Categories() on pc.CategoryId equals c.Id
                        where c.Id == categoryId && p.PublishedDate.HasValue == true
                        select p).OrderByDescending(p => p.PublishedDate).GetPage(pageNumber, pageSize);
            }
        }

        //public IList<BlogPost> GetAll(Guid blogId)
        //{
        //    using (var contextManager = CreateContextManager(true))
        //    {
        //        return ProjectPosts(contextManager.Context, GetPostsQuery(contextManager.Context, blogId)).ToList();
        //    }
        //}

        public void Delete(Guid postId)
        {
            var post = Get(postId);
            if (post != null)
            {
                using (var contextManager = CreateContextManager(false))
                {
                    contextManager.Context.Posts().DeleteOnSubmit(post);
                    contextManager.Commit();
                }
            }
        }

        public void Update(BlogPost post)
        {
            using (var contextManager = CreateContextManager(false))
            {
                contextManager.Commit();
            }
        }

        public void Add(BlogPost post)
        {
            using (var contextManager = CreateContextManager(false))
            {
                contextManager.Context.Posts().InsertOnSubmit(post);
                contextManager.Commit();
            }
        }

        public int GetPostsCount(Guid blogId)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().Count(p => p.BlogId == blogId && p.PublishedDate.HasValue);
            }
        }

        public BlogPost Get(string postName, Guid blogId, bool onlyVisible)
        {
            using (var contextManager = CreateContextManager(true))
            {
                return contextManager.Context.Posts().SingleOrDefault(p => p.BlogId == blogId && (onlyVisible ? p.PublishedDate.HasValue : true) && p.Slug == postName);
            }
        }

        public void DeleteAll(Guid blogId)
        {
            //using (var contextManager = CreateContextManager(false))
            //{
            //    var postCategories = from p in contextManager.Context.Posts()
            //                         join c in contextManager.Context.PostCategories() on p.Id equals c.PostId
            //                         where p.BlogId == blogId
            //                         select c;

            //    var postTags = from p in contextManager.Context.Posts()
            //                   join t in contextManager.Context.PostTags() on p.Id equals t.PostId
            //                   where p.BlogId == blogId
            //                   select t;

            //    var postNotifies = from p in contextManager.Context.Posts()
            //                       join n in contextManager.Context.Notifies() on p.Id equals n.PostId
            //                       where p.BlogId == blogId
            //                       select n;

            //    var postComments = from p in contextManager.Context.Posts()
            //                       join c in contextManager.Context.Comments() on p.Id equals c.PostId
            //                       where p.BlogId == blogId
            //                       select c;
            //    var posts = contextManager.Context.Posts().Where(p => p.BlogId == blogId);

            //    contextManager.Context.PostCategories().DeleteAllOnSubmit(postCategories);
            //    contextManager.Context.PostTags().DeleteAllOnSubmit(postTags);
            //    contextManager.Context.Notifies().DeleteAllOnSubmit(postNotifies);
            //    contextManager.Context.Comments().DeleteAllOnSubmit(postComments);
            //    contextManager.Context.Posts().DeleteAllOnSubmit(posts);
            //    contextManager.Commit();
            //}
        }

        #region Private methods


        //private IQueryable<BlogPost> GetTagPostsQuery(DataContext context, BlogTagBase tag)
        //{
        //    return from p in context.Posts()
        //           join pt in context.PostTags() on p.Id equals pt.PostId
        //           join t in context.Tags() on pt.TagId equals t.Id
        //           where t.Id == tag.Id
        //           select p;
        //}

        //private IQueryable<BlogPost> GetCategoryPostsQuery(DataContext context, BlogCategory category)
        //{
        //    return from p in context.Posts()
        //           join pc in context.PostCategories() on p.Id equals pc.PostId
        //           join c in context.Categories() on pc.CategoryId equals c.Id
        //           where c.Id == category.Id
        //           select p;
        //}

        //private IQueryable<BlogPost> GetPostsQuery(DataContext context, Guid blogId)
        //{
        //    return from p in context.Posts()
        //           where p.BlogId == blogId
        //           select p;
        //}

        //private IQueryable<BlogPost> ProjectPosts(DataContext context, IQueryable<BlogPost> posts)
        //{
        //    return (from p in posts
        //            let c = GetCategories(context, p.Id)
        //            let t = GetTags(context, p.Id)
        //            let com = GetComments(context, p.Id)
        //            orderby p.CreatedDate descending
        //            select new BlogPost
        //            {
        //                Author = p.Author,
        //                CreatedDate = p.CreatedDate,
        //                Description = p.Description,
        //                Id = p.Id,
        //                IsCommentEnabled = p.IsCommentEnabled,
        //                PublishedDate = p.PublishedDate,
        //                Keywords = p.Keywords,
        //                ModifiedDate = p.ModifiedDate,
        //                BlogId = p.BlogId,
        //                PostContent = p.PostContent,
        //                Rating = p.Rating,
        //                Slug = p.Slug,
        //                Title = p.Title,
        //                Categories = c.ToList(),
        //                Tags = t.ToList(),
        //                Comments = com.ToList()
        //            });
        //}

        //private IQueryable<BlogCategory> GetCategories(DataContext context, Guid postId)
        //{
        //    return from cp in context.PostCategories()
        //           join c in context.Categories() on cp.CategoryId equals c.Id
        //           where cp.PostId == postId
        //           select c;
        //}

        //private IQueryable<BlogPostComment> GetComments(DataContext context, Guid postId)
        //{
        //    return from cp in context.Comments()
        //           where cp.PostId == postId
        //           orderby cp.CreatedDate ascending
        //           select cp;
        //}

        //private IQueryable<BlogTagBase> GetTags(DataContext context, Guid postId)
        //{
        //    return from pt in context.PostTags()
        //           join t in context.Tags() on pt.TagId equals t.Id
        //           where pt.PostId == postId
        //           select t;
        //}

        #endregion
    }
}
